home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / javax / swing / KeyStroke.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  15.9 KB  |  416 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)KeyStroke.java    1.28 98/08/28
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14. package javax.swing;
  15.  
  16. import java.awt.event.KeyEvent;
  17. import java.awt.event.InputEvent;
  18. import java.util.Hashtable;
  19. import java.io.Serializable;
  20.  
  21. /**
  22.  * A KeyStroke instance represents a key being typed on the keyboard -- it
  23.  * contains both a char code for the key and a modifier (alt, shift, ctrl, 
  24.  * meta, or a combination). 
  25.  * <p>
  26.  * KeyStroke objects are used to define high-level (semantic) action events.
  27.  * Instead of trapping every keystroke and throwing away the ones you are
  28.  * not interested in, those keystrokes you care about automatically initiate
  29.  * actions on the components they are registered with. 
  30.  * <p>
  31.  * KeyStroke objects handle both character-code generating keystrokes you 
  32.  * would trap with a KeyTyped event handler and key-code generating keystrokes
  33.  * (like Enter or F1) that you would trap with a KeyPressed event handler.
  34.  * <p>
  35.  * KeyStroke objects are immutable and unique.
  36.  * <p>
  37.  * All KeyStroke objects are cached. To get one, use <code>getKeyStroke</code>.
  38.  * <p>
  39.  * <strong>Warning:</strong>
  40.  * Serialized objects of this class will not be compatible with 
  41.  * future Swing releases.  The current serialization support is appropriate
  42.  * for short term storage or RMI between applications running the same
  43.  * version of Swing.  A future release of Swing will provide support for
  44.  * long term persistence.
  45.  *
  46.  * @see JComponent#registerKeyboardAction
  47.  * @see #getKeyStroke
  48.  *
  49.  * @version 1.28 08/28/98
  50.  * @author Arnaud Weber
  51.  */
  52. public class KeyStroke implements Serializable {
  53.     private static final Object pressedCharCacheKey = 
  54.         new StringBuffer("KeyStroke.pressedCharCacheKey");
  55.     private static final Object releasedCharCacheKey = 
  56.         new StringBuffer("KeyStroke.releasedCharCacheKey");
  57.     private static final Object pressedCodeCacheKey = 
  58.         new StringBuffer("KeyStroke.pressedCodeCacheKey");
  59.     private static final Object releasedCodeCacheKey = 
  60.         new StringBuffer("KeyStroke.releasedCodeCacheKey");
  61.  
  62.     char keyChar;
  63.     int  keyCode;
  64.     int  modifiers;
  65.     boolean onKeyRelease;
  66.  
  67.     /* We cache 114 key stroke with keyChar (1368 bytes) */
  68.     /* We cache 114 * 8 key stroke with keyCode and popular modifiers (10944 bytes) */ 
  69.     /* Total cache is around 11K */
  70.  
  71.     static final int MIN_ASCII_CACHE_INDEX = '\n'; 
  72.     static final int MAX_ASCII_CACHE_INDEX = 0x7F;
  73.     /* It is impossible to instantiate a KeyStroke. Use getKeyStroke() instead **/
  74.     private KeyStroke() {
  75.         
  76.     }
  77.  
  78.     static KeyStroke getCachedKeyCharKeyStroke(char keyChar,boolean onKeyRelease) {
  79.         KeyStroke result = null;
  80.         if(keyChar >= MIN_ASCII_CACHE_INDEX && keyChar < MAX_ASCII_CACHE_INDEX) {
  81.             synchronized(KeyStroke.class) {
  82.                 KeyStroke cache[];
  83.                 if(onKeyRelease) 
  84.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  85.                         releasedCharCacheKey);
  86.                 else
  87.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  88.                         pressedCharCacheKey);
  89.                 if(cache != null)
  90.                     result = cache[((int)keyChar) - MIN_ASCII_CACHE_INDEX];
  91.             }
  92.         }
  93.         return result;
  94.     }
  95.  
  96.     static void cacheKeyCharKeyStroke(KeyStroke ks,boolean onKeyRelease) {
  97.         if(ks.keyChar >= MIN_ASCII_CACHE_INDEX && ks.keyChar < MAX_ASCII_CACHE_INDEX) {
  98.             synchronized(KeyStroke.class) {
  99.                 if(onKeyRelease) {
  100.                     KeyStroke releasedKeyCharKeyStrokeCache[] = (KeyStroke[])
  101.                         SwingUtilities.appContextGet(releasedCharCacheKey);
  102.                     if(releasedKeyCharKeyStrokeCache == null) {
  103.                         releasedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  104.                         SwingUtilities.appContextPut(
  105.                             releasedCharCacheKey, releasedKeyCharKeyStrokeCache);
  106.                     }
  107.                     releasedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  108.                 } else {
  109.                     KeyStroke pressedKeyCharKeyStrokeCache[] = (KeyStroke[])
  110.                         SwingUtilities.appContextGet(pressedCharCacheKey);
  111.                     if(pressedKeyCharKeyStrokeCache == null) {
  112.                         pressedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  113.                         SwingUtilities.appContextPut(
  114.                             pressedCharCacheKey, pressedKeyCharKeyStrokeCache);
  115.                     }
  116.                     pressedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  117.                 }
  118.             }
  119.         }
  120.     }
  121.  
  122.     static int subIndexForModifier(int modifiers) {
  123.         if(modifiers == 0)
  124.             return 0;
  125.         else if(modifiers == InputEvent.SHIFT_MASK)
  126.             return 1;
  127.         else if(modifiers == InputEvent.CTRL_MASK)
  128.             return 2;
  129.         else if(modifiers == InputEvent.ALT_MASK)
  130.             return 3;
  131.         
  132.         return -1;
  133.     }
  134.  
  135.     static KeyStroke getCachedKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  136.         int subIndex;
  137.         KeyStroke result = null;
  138.         if(keyCode >= MIN_ASCII_CACHE_INDEX && keyCode < MAX_ASCII_CACHE_INDEX &&
  139.            (subIndex = subIndexForModifier(modifiers)) != -1) {
  140.             synchronized(KeyStroke.class) {
  141.                 KeyStroke cache[][];
  142.                 if(onKeyRelease) 
  143.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  144.                         pressedCodeCacheKey);
  145.                 else
  146.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  147.                         releasedCodeCacheKey);
  148.  
  149.                 if(cache != null)
  150.                     result = cache[subIndex][keyCode - MIN_ASCII_CACHE_INDEX];
  151.             }
  152.         }
  153.         return result;
  154.     }
  155.  
  156.     static void cacheKeyStroke(KeyStroke ks) {
  157.         int subIndex = -1;
  158.         if(ks.keyCode >= MIN_ASCII_CACHE_INDEX && ks.keyCode < MAX_ASCII_CACHE_INDEX &&
  159.            (subIndex = subIndexForModifier(ks.modifiers)) != -1) {
  160.             synchronized(KeyStroke.class) {
  161.                 KeyStroke cache[][] = null;
  162.                 if(ks.onKeyRelease) {
  163.                     KeyStroke[][] pressedKeyCodeKeyStrokeCache = (KeyStroke[][])
  164.                         SwingUtilities.appContextGet(pressedCodeCacheKey);
  165.                     if(pressedKeyCodeKeyStrokeCache == null) {
  166.                         pressedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  167.                                                                          MIN_ASCII_CACHE_INDEX];
  168.                         SwingUtilities.appContextPut(
  169.                             pressedCodeCacheKey, pressedKeyCodeKeyStrokeCache);
  170.                     }
  171.                     cache = pressedKeyCodeKeyStrokeCache;
  172.                 } else {
  173.                     KeyStroke[][] releasedKeyCodeKeyStrokeCache = (KeyStroke[][])
  174.                         SwingUtilities.appContextGet(releasedCodeCacheKey);
  175.                     if(releasedKeyCodeKeyStrokeCache == null) {
  176.                         releasedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  177.                                                                           MIN_ASCII_CACHE_INDEX];
  178.                         SwingUtilities.appContextPut(
  179.                             releasedCodeCacheKey, releasedKeyCodeKeyStrokeCache);
  180.                     }
  181.                     cache = releasedKeyCodeKeyStrokeCache;
  182.                 }
  183.  
  184.                 cache[subIndex][ks.keyCode - MIN_ASCII_CACHE_INDEX] = ks;
  185.             }
  186.         }
  187.     }
  188.     
  189.     /**
  190.      * Return a shared instance of a key stroke that is
  191.      * activated when the key is pressed (i.e. a KeyStroke
  192.      * for the KeyEvent.KEY_TYPED event).
  193.      *
  194.      * @param keyChar the character value for a keyboard key
  195.      * @return a KeyStroke object for that key
  196.      */
  197.     public static KeyStroke getKeyStroke(char keyChar) {
  198.         return getKeyStroke(keyChar,false);
  199.     }
  200.  
  201.     /**
  202.      * Return a shared instance of a key stroke, specifying
  203.      * whether the key is considered to be activated when it is 
  204.      * pressed or when it is released.
  205.      *
  206.      * @param keyChar the character value for a keyboard key
  207.      * @param onKeyRelease a boolean value. When true, specifies that
  208.      *        the key is active when it is released.
  209.      * @return a KeyStroke object for that key
  210.      * @deprecated use getKeyStroke(char)
  211.      */
  212.     public static KeyStroke getKeyStroke(char keyChar,boolean onKeyRelease) {
  213.         KeyStroke result = getCachedKeyCharKeyStroke(keyChar,onKeyRelease);
  214.  
  215.         if(result == null) {
  216.             result = new KeyStroke();
  217.             result.keyChar = keyChar;
  218.             result.modifiers = 0;
  219.             result.onKeyRelease = onKeyRelease;
  220.             cacheKeyCharKeyStroke(result,onKeyRelease);
  221.         }
  222.         return result;
  223.     }
  224.  
  225.     /**
  226.      * Return a shared instance of a key stroke given a numeric keycode and a set
  227.      * of modifiers, specifying whether the key is activated when it is pressed
  228.      * or released.
  229.      * <p>
  230.      * The "virtual key" constants defined in java.awt.event.KeyEvent can be 
  231.      * used to specify the key code. For example:<ul>
  232.      * <li>java.awt.event.KeyEvent.VK_ENTER 
  233.      * <li>java.awt.event.KeyEvent.VK_TAB
  234.      * <li>java.awt.event.KeyEvent.VK_SPACE
  235.      * </ul>
  236.      * The modifiers consist of any combination of:<ul>
  237.      * <li>java.awt.Event.SHIFT_MASK (1)
  238.      * <li>java.awt.Event.CTRL_MASK (2)
  239.      * <li>java.awt.Event.META_MASK (4)
  240.      * <li>java.awt.Event.ALT_MASK (8)
  241.      * </ul>
  242.      * Since these numbers are all different powers of two, any combination of
  243.      * them is an integer in which each bit represents a different
  244.      * modifier key.
  245.      *
  246.      * @param keyCode an int specifying the numeric code for a keyboard key
  247.      * @param modifiers an int specifying any combination of the key modifiers.
  248.      * @param onKeyRelease a boolean value. When true, specifies that
  249.      *        the key is active when it is released.
  250.      * @return a KeyStroke object for that key
  251.      *
  252.      * @see java.awt.event.KeyEvent
  253.      * @see java.awt.Event
  254.      */
  255.     public static KeyStroke getKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  256.         KeyStroke result = getCachedKeyStroke(keyCode,modifiers,onKeyRelease);
  257.  
  258.         if(result == null) {
  259.             result = new KeyStroke();
  260.             result.keyCode = keyCode;
  261.             result.modifiers = modifiers;
  262.             result.onKeyRelease = onKeyRelease;
  263.             cacheKeyStroke(result);
  264.         }
  265.  
  266.         return result;
  267.     }
  268.  
  269.     /**
  270.      * Return a shared instance of a key stroke given a char code and a set
  271.      * of modifiers -- the key is activated when it is pressed.
  272.      * <p>
  273.      * <p>
  274.      * The "virtual key" constants defined in java.awt.event.KeyEvent can be 
  275.      * used to specify the key code. For example:<ul>
  276.      * <li>java.awt.event.KeyEvent.VK_ENTER 
  277.      * <li>java.awt.event.KeyEvent.VK_TAB
  278.      * <li>java.awt.event.KeyEvent.VK_SPACE
  279.      * </ul>
  280.      * The modifiers consist of any combination of:<ul>
  281.      * <li>java.awt.Event.SHIFT_MASK (1)
  282.      * <li>java.awt.Event.CTRL_MASK (2)
  283.      * <li>java.awt.Event.META_MASK (4)
  284.      * <li>java.awt.Event.ALT_MASK (8)
  285.      * </ul>
  286.      * Since these numbers are all different powers of two, any combination of
  287.      * them is an integer in which each bit represents a different
  288.      * modifier key.
  289.      *
  290.      * @param keyCode an int specifying the numeric code for a keyboard key
  291.      * @param modifiers an int specifying any combination of the key modifiers.
  292.      * @return a KeyStroke object for that key
  293.      * @see java.awt.event.KeyEvent
  294.      */
  295.     public static KeyStroke getKeyStroke(int keyCode,int modifiers) {
  296.         return getKeyStroke(keyCode,modifiers,false);
  297.     }
  298.  
  299.     /**
  300.      * Return a keystroke from an event.
  301.      * <p>
  302.      * This method obtains the keyChar from a KeyTyped event,
  303.      * and the keyCode from a KeyPressed or KeyReleased event,
  304.      * so you the type of event doesn't matter.
  305.      *
  306.      * @param anEvent the KeyEvent to obtain the KeyStroke from
  307.      * @return the KeyStroke that precipitated the event
  308.      */
  309.     public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
  310.         KeyStroke ks = null;
  311.         switch(anEvent.getID()) {
  312.         case KeyEvent.KEY_PRESSED:
  313.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),false);
  314.             break;
  315.         case KeyEvent.KEY_RELEASED:
  316.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),true);
  317.             break;
  318.         case KeyEvent.KEY_TYPED:
  319.             ks = getKeyStroke(anEvent.getKeyChar());
  320.             break;
  321.         }
  322.         return ks;
  323.     }
  324.  
  325.     /**
  326.      * Return a shared instance of a key stroke matching a string
  327.      * representation.
  328.      *
  329.      * @param representation a String specifying a KeyStroke
  330.      * @return a KeyStroke object matching the specification. 
  331.      */
  332.     public static KeyStroke getKeyStroke(String representation) {
  333.         // Not implemented
  334.         return null;
  335.     }
  336.  
  337.     /**
  338.      * Returns the character defined by this KeyStroke object.
  339.      * @return a char value
  340.      * @see #getKeyStroke(char)
  341.      */
  342.     public char getKeyChar() { return keyChar; }
  343.     /**
  344.      * Returns the numeric keycode defined by this KeyStroke object.
  345.      * @return an int containing the keycode value
  346.      * @see #getKeyStroke(int,int)
  347.      */
  348.     public int  getKeyCode() { return keyCode; }
  349.     /**
  350.      * Returns the modifier keys defined by this KeyStroke object.
  351.      * @return an int containing the modifiers
  352.      * @see #getKeyStroke(int,int)
  353.      */
  354.     public int getModifiers() { return modifiers; }
  355.     /**
  356.      * Returns true if this keystroke is active on key release.
  357.      * @return true if active on key release, false if active on key press
  358.      * @see #getKeyStroke(int,int,boolean)
  359.      */
  360.     public boolean isOnKeyRelease() { return onKeyRelease; }
  361.  
  362.     private static String getStringRepresentation(char keyChar,int modifiers,boolean kr) {
  363.         return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar +  
  364.             (kr?"-R":"-P");
  365.     }
  366.  
  367.     private static String getStringRepresentation(int keyCode,int modifiers,boolean kr) {
  368.         return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) + KeyEvent.getKeyText(keyCode) +
  369.             (kr?"-R":"-P");
  370.     }
  371.  
  372.     /**
  373.      * Returns a numeric value for this object that is likely to be
  374.      * reasonably unique, so it can be used as the index value in a
  375.      * Hashtable.
  376.      *
  377.      * @return an int that "represents" this object
  378.      * @see java.util.Hashtable
  379.      */
  380.     public int hashCode() {
  381.         return (((int) keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers+1) +
  382.             (onKeyRelease ? 1 : 2);
  383.     }
  384.  
  385.     /**
  386.      * Returns true if this object is identical to the specified object.
  387.      *
  388.      * @param anObject the Object to compare this object to
  389.      * @return true if the objects are identical
  390.      */
  391.     public boolean equals(Object anObject) {
  392.         if(anObject instanceof KeyStroke) {
  393.             KeyStroke ks = (KeyStroke) anObject;
  394.             if(ks.keyChar == keyChar && ks.keyCode == keyCode && 
  395.                ks.onKeyRelease == onKeyRelease && ks.modifiers == modifiers)
  396.                 return true;
  397.         }
  398.         return false;
  399.     }
  400.  
  401.     /**
  402.      * Returns a string that displays and identifies this
  403.      * object's properties.
  404.      *
  405.      * @return a String representation of this object
  406.      */
  407.     public String toString() {
  408.         if(keyChar == 0)
  409.             return getStringRepresentation(keyCode,modifiers,onKeyRelease);
  410.         else
  411.             return getStringRepresentation(keyChar,0,onKeyRelease);
  412.     }
  413. }
  414.  
  415.  
  416.